//////////////////////////////////////////////////////////////////////////
//
// This file is a part of XORT project.
//
// PROJECT:         Xort compiler execution subsystem
// FILE:            XortJit64.h - JIT code generator for x64 bit architecture
// AUTHOR:          Vladimir Gumenuk
// DATE:            7-Oct-2014
// MODIFICATIONS:
//
//
//     Copyright(c) 2014, Vladimir Gumenuk
//     All rights reserved.
//
//     Redistribution and use in source and binary forms, with or without modification, 
//     are permitted provided that the following conditions are met :
//
//     1. Redistributions of source code must retain the above copyright notice, 
//        this list of conditions and the following disclaimer.
//     2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 
//        the following disclaimer in the documentation and / or other materials provided with the distribution.
//     3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse 
//        or promote products derived from this software without specific prior written permission.
//
//     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
//     ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
//     OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 
//     THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
//     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
//     OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
//     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
//     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
//     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#pragma once


#include "xgendefs.h"
#include "XortMachine.h"

class XStorageStack : public xarray<VarStorage, CCopySimpleType<VarStorage>, CDeleteSimpleType<VarStorage> >
{
public:
    // for simplified stack implementation
    inline VarStorage& top() {
        return m_pItems[m_dwCount - 1];
    }

    inline bool canPop() const {
        return m_dwCount > 0 ? true : false;
    }

    inline VarStorage pop() {
        m_dwCount -= 1;
        VarStorage x = m_pItems[m_dwCount];
        m_pItems[m_dwCount].Clear();
        return x;
    }

    // returns the index of the element
    inline dword push( const VarStorage& Item ) {
        return add( Item );
    }
};

class XGenerator;

//////////////////////////////////////////////////////////////////////////
// Generates the object code for x64 architecture (experimental).
// It uses metainstructions to perform direct translation from intermediate instruction to object code.
// The result is a good start point for limitless optimizations 
class XortJit64
{
public:
    XortJit64();
    virtual ~XortJit64();

    int CreateDataBlock( XCELLSARRAY& globalVars ); // create and initialize global variables block
    int ProcessMethods( SYMBOLSARRAY& globalFunc ); // generate object code for each global function
    
private:
    dword calcCodeSize( const SYMBOLSARRAY& globalFunc );
    int   ProcessFunction( Symbol *pFunc, dword& dwCodeSizeOut );
    int   ProcessXortRegularProc( Symbol *pFunc, dword& dwCodeSizeOut );
    dword GetLocalVariablesCount( Symbol *pFunc );  // returns the number of local variables (stkvar based calculation)
    int   ProcessMetaInstructions( Symbol *pFunc );
    int   ProcessPrimitive( const InstructionData& instr );
    void  gen_Prologue();
    void  gen_Epilogue();

    inline dword getCurInstrIdx() const { return m_dwInstrIdx; }
    InstructionData* getNextInstruction();
    InstructionData* getCurInstruction();

    int xvmStackIdxToMachineIdx( int iXortIdx ); // converts stack index from xvm to hardware stack index
    
    int   do_begswitch();
    int   do_beginret();
    int   do_beginasgn();
    int   do_begin_if();
    int   do_begincall();
    int   do_stkvar();
    int   do_label( int iIdx );

    int gen_load( const InstructionData& primData );
    int gen_store( const InstructionData& primData );
    int gen_ret( const InstructionData& primData );

    int gen_load_const_operand( const VarStorage& st, const XortElement& val );
    int gen_load_mem_operand( const VarStorage& st, qword qwAddr, const XortElement& val );
    int gen_store_operand_mem( QWORD qwAddrDst, VarStorage stSrc, byte bType );
    int gen_load_stack_operand( VarStorage stDst, int iStkIdx, byte bType );
    int gen_store_stack_operand( int iStkIdxDst, VarStorage stSrc, byte bType );
    int gen_push_operand( VarStorage stSrc );

    void deref_reg( Register64 rg, const XortElement& val ); // mov reg, [reg]
    void mov_reg_imm_Value( Register64 rg, const XortElement& val );
    void push_imm_Value( const XortElement& val );
    void store_mem_reg( QWORD qwAddr, Register64 rg, byte bType );
    void store_mem_stack( QWORD qwAddr, int iIdx, byte bType );
    void mov_reg_stack( Register64 rg, int iStkIdx, byte bType );
    void mov_stack_reg( int iStkIdx, Register64 rg, byte bType );


    typedef xarray< qword, CCopySimpleType<qword>, CDeleteSimpleType<qword> > POINTERS_ARRAY;

    XCELLSARRAY        *m_pGlobalVars;  // Xort global variables block
    POINTERS_ARRAY      m_dataPointers; // array, that store the pointers to variables in global data block, so pointer can be found by variable index
    void               *m_pDATA;        // global data block

    POINTERS_ARRAY      m_funcPointers; // array, that store the pointers to functions in global code block, so pointer can be found by function index
    void               *m_pCODE;        // object code block

    dword               m_dwInstrIdx;   // current instruction index
    Symbol             *m_pCurProc;     // current procedure being processed
    XGenerator         *m_pGenerator;   // object code generator

    XortMachine         m_Machine;      // cpu + hardware stack emulator during code generation
    XStorageStack       m_Operands;     // stores location of each operand from m_Machine
};
